home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 253 / Issue 253 - March 2009 - DPCS0309DVD.ISO / Toolkit / Internet / WinHTTrack / httrack-3.43.exe / {app} / src / htsname.c < prev    next >
Encoding:
C/C++ Source or Header  |  1980-01-01  |  51.8 KB  |  1,520 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: httrack.c subroutines:                                 */
  34. /*       savename routine (compute output filename)             */
  35. /* Author: Xavier Roche                                         */
  36. /* ------------------------------------------------------------ */
  37.  
  38. /* Internal engine bytecode */
  39. #define HTS_INTERNAL_BYTECODE
  40.  
  41. #include "htscore.h"
  42. #include "htsname.h"
  43. #include "md5.h"
  44. #include "htsmd5.h"
  45. #include "htstools.h"
  46. #include <ctype.h>
  47.  
  48. #undef test_flush
  49. #define test_flush if (opt->flush) { fflush(opt->log); fflush(opt->log); }
  50.  
  51. #define ADD_STANDARD_PATH \
  52.     {  /* ajout nom */\
  53.       char BIGSTK buff[HTS_URLMAXSIZE*2];\
  54.       buff[0]='\0';\
  55.       strncatbuff(buff,start_pos,(int) (nom_pos - start_pos));\
  56.       url_savename_addstr(save,buff);\
  57.     }
  58.  
  59. #define ADD_STANDARD_NAME(shortname) \
  60.     {  /* ajout nom */\
  61.       char BIGSTK buff[HTS_URLMAXSIZE*2];\
  62.       standard_name(buff,dot_pos,nom_pos,fil_complete,(shortname));\
  63.       url_savename_addstr(save,buff);\
  64.     }
  65.  
  66.  
  67. /* Avoid stupid DOS system folders/file such as 'nul' */
  68. /* Based on linux/fs/umsdos/mangle.c */
  69. static const char *hts_tbdev[] =
  70. {
  71.     "/prn", "/con", "/aux", "/nul",
  72.     "/lpt1", "/lpt2", "/lpt3", "/lpt4",
  73.     "/com1", "/com2", "/com3", "/com4",
  74.     "/clock$",
  75.     "/emmxxxx0", "/xmsxxxx0", "/setverxx",
  76.     ""
  77. };
  78.  
  79.  
  80. #define URLSAVENAME_WAIT_FOR_AVAILABLE_SOCKET() do { \
  81.   int prev = opt->state._hts_in_html_parsing; \
  82.   while(back_pluggable_sockets_strict(sback, opt) <= 0) { \
  83.     opt->state. _hts_in_html_parsing = 6; \
  84.     /* Wait .. */ \
  85.     back_wait(sback,opt,cache,0); \
  86.     /* Transfer rate */ \
  87.     engine_stats(); \
  88.     /* Refresh various stats */ \
  89.     HTS_STAT.stat_nsocket=back_nsoc(sback); \
  90.     HTS_STAT.stat_errors=fspc(opt,NULL,"error"); \
  91.     HTS_STAT.stat_warnings=fspc(opt,NULL,"warning"); \
  92.     HTS_STAT.stat_infos=fspc(opt,NULL,"info"); \
  93.     HTS_STAT.nbk=backlinks_done(sback,liens,lien_tot,ptr); \
  94.     HTS_STAT.nb=back_transfered(HTS_STAT.stat_bytes,sback); \
  95.     /* Check */ \
  96.     { \
  97.       if (!RUN_CALLBACK7(opt, loop, sback->lnk, sback->count,-1,ptr,lien_tot,(int) (time_local()-HTS_STAT.stat_timestart),&HTS_STAT)) { \
  98.         return -1; \
  99.       } \
  100.     } \
  101.   } \
  102.   opt->state._hts_in_html_parsing = prev; \
  103. } while(0)
  104.  
  105.  
  106. // forme le nom du fichier α sauver (save) α partir de fil et adr
  107. // systΦme intelligent, qui renomme en cas de besoin (exemple: deux INDEX.HTML et index.html)
  108. int url_savename(char* adr_complete, char* fil_complete, char* save, 
  109.                                  char* former_adr, char* former_fil, 
  110.                                  char* referer_adr, char* referer_fil, 
  111.                                  httrackp* opt, 
  112.                                  lien_url** liens, int lien_tot, 
  113.                                  struct_back* sback, cache_back* cache, hash_struct* hash, 
  114.                                  int ptr, int numero_passe, const lien_back* headers) {
  115.     char catbuff[CATBUFF_SIZE];
  116.   const char* mime_type = ( headers && !HTTP_IS_REDIRECT(headers->r.statuscode) ) ? headers->r.contenttype : NULL;
  117.   /*const char* mime_type = ( headers && HTTP_IS_OK(headers->r.statuscode) ) ? headers->r.contenttype : NULL;*/
  118.   lien_back* const back = sback->lnk;
  119.   /* */
  120.   char BIGSTK newfil[HTS_URLMAXSIZE*2];   /* ="" */
  121.   /*char BIGSTK normadr_[HTS_URLMAXSIZE*2];*/
  122.   char BIGSTK normadr_[HTS_URLMAXSIZE*2], normfil_[HTS_URLMAXSIZE*2];
  123.     enum { PROTOCOL_HTTP, PROTOCOL_HTTPS, PROTOCOL_FTP, PROTOCOL_FILE, PROTOCOL_MMS, PROTOCOL_UNKNOWN };
  124.   static const char* protocol_str[] = {"http", "https", "ftp", "file", "mms", "unknown"};
  125.   int protocol = PROTOCOL_HTTP;
  126.   char* normadr;
  127.   char* normfil;
  128.   char* fil;
  129.   char* adr;
  130.   char* print_adr;
  131.   char *start_pos=NULL,*nom_pos=NULL,*dot_pos=NULL;  // Position nom et point
  132.   // pour changement d'extension ou de nom (content-disposition)
  133.   int ext_chg=0, ext_chg_delayed=0;
  134.   int is_html=0;
  135.   char ext[256];
  136.   int max_char=0;
  137.   //CLEAR
  138.   newfil[0]=ext[0]='\0';
  139.  
  140.   /* 8-3 ? */
  141.   switch(opt->savename_83) {
  142.   case 1:     // 8-3
  143.     max_char=8;
  144.     break;
  145.   case 2:     // Level 2 File names may be up to 31 characters.
  146.     max_char=31;
  147.     break;
  148.   default:
  149.     max_char=8;
  150.     break;
  151.   }
  152.  
  153.   // effacer save
  154.   save[0]='\0';
  155.   // fil
  156.   fil = fil_complete;
  157.   // copy of fil, used for lookups (see urlhack)
  158.   normfil = fil;
  159.   // et adr (sauter user/pass)
  160.   // on prend le parti de mettre les fichiers avec login/pass au mΩme endroit que si ils
  161.   // Θtaient capturΘs sans ces paramΦtres
  162.   // c'est pour cette raison qu'on ignore totalement adr_complete (mΩme pour la recherche en table de hachage)
  163.   adr = jump_identification(adr_complete);
  164.   // copy of adr, used for lookups (see urlhack)
  165.   normadr = adr;
  166.  
  167.   // normalize the URL:
  168.   // www.foo.com -> foo.com
  169.   // www-42.foo.com -> foo.com
  170.   // foo.com/bar//foobar -> foo.com/bar/foobar
  171.   if (opt->urlhack) {
  172.     // copy of adr (without protocol), used for lookups (see urlhack)
  173.     normadr=adr_normalized(adr, normadr_);
  174.     normfil=fil_normalized(fil,normfil_);
  175.   } else {
  176.     if (link_has_authority(adr_complete)) {     // https or other protocols : in "http/" subfolder
  177.       char* pos = strchr(adr_complete, ':');
  178.       if (pos != NULL) {
  179.         normadr_[0] = '\0';
  180.         strncatbuff(normadr_, adr_complete, (int)(pos - adr_complete));
  181.         strcatbuff(normadr_, "://");
  182.         strcatbuff(normadr_, normadr);
  183.         normadr=normadr_;
  184.       }
  185.     }
  186.   }
  187.  
  188.   // α afficher sans ftp://
  189.   print_adr=jump_protocol(adr);
  190.   if (strfield(adr_complete, "https:")) {
  191.       protocol = PROTOCOL_HTTPS;
  192.   } else if (strfield(adr_complete, "ftp:")) {
  193.       protocol = PROTOCOL_FTP;
  194.   } else if (strfield(adr_complete, "file:")) {
  195.       protocol = PROTOCOL_FILE;
  196.   } else if (strfield(adr_complete, "mms:")) {
  197.       protocol = PROTOCOL_MMS;
  198.   } else {
  199.       protocol = PROTOCOL_HTTP;
  200.   }
  201.  
  202.   // court-circuit pour lien primaire
  203.   if (strnotempty(adr)==0) {
  204.     if (strcmp(fil,"primary")==0) {
  205.       strcatbuff(save,"primary.html");
  206.       return 0;
  207.     }
  208.   }
  209.  
  210.  
  211.   // vΘrifier que le nom n'a pas dΘja ΘtΘ calculΘ (si oui le renvoyer tel que)
  212.   // vΘrifier que le nom n'est pas dΘja pris...
  213.   // NOTE: si on cherche /toto/ et que /toto est trouvΘ on le prend (et rΘciproquqment) ** // **
  214.   if (liens!=NULL) { 
  215.     int i;
  216.  
  217.     i=hash_read(hash,normadr,normfil,1,opt->urlhack);      // recherche table 1 (adr+fil)
  218.     if (i>=0) {    // ok, trouvΘ
  219.       strcpybuff(save,liens[i]->sav);
  220.       return 0;
  221.     }
  222.     i=hash_read(hash,normadr,normfil,2,opt->urlhack);      // recherche table 2 (former_adr+former_fil)
  223.     if (i>=0) {    // ok, trouvΘ
  224.       // copier location moved!
  225.       strcpybuff(adr_complete,liens[i]->adr);
  226.       strcpybuff(fil_complete,liens[i]->fil);
  227.       // et save
  228.       strcpybuff(save,liens[i]->sav);  // copier (formΘ α partir du nouveau lien!)
  229.       return 0;
  230.     }
  231.  
  232.     // chercher sans / ou avec / dans former
  233.     {
  234.       char BIGSTK fil_complete_patche[HTS_URLMAXSIZE*2];
  235.       strcpybuff(fil_complete_patche,normfil);
  236.       // Version avec ou sans /
  237.       if (fil_complete_patche[strlen(fil_complete_patche)-1]=='/')
  238.         fil_complete_patche[strlen(fil_complete_patche)-1]='\0';
  239.       else
  240.         strcatbuff(fil_complete_patche,"/");
  241.       i=hash_read(hash,normadr,fil_complete_patche,2,opt->urlhack);      // recherche table 2 (former_adr+former_fil)
  242.       if (i>=0) {
  243.         // Θcraser fil et adr (pas former_fil?????)
  244.         strcpybuff(adr_complete,liens[i]->adr);
  245.         strcpybuff(fil_complete,liens[i]->fil);
  246.         // Θcrire save
  247.         strcpybuff(save,liens[i]->sav);
  248.         return 0;
  249.       }
  250.     }
  251.   }
  252.  
  253.   // vΘrifier la non prΘsence de paramΦtres dans le nom de fichier
  254.   // si il y en a, les supprimer (ex: truc.cgi?subj=aspirateur)
  255.   // nΘanmoins, gardΘ pour vΘrifier la non duplication (voir aprΦs)
  256.   {
  257.     char* a;
  258.     a=strchr(fil,'?');
  259.     if (a!=NULL) {
  260.       strncatbuff(newfil,fil,(int) (a - fil));
  261.     } else {
  262.       strcpybuff(newfil,fil);
  263.     }
  264.     fil=newfil;
  265.   }
  266.   // Decode remaining %
  267.   strcpybuff(fil,unescape_http(catbuff,fil));
  268.     // , BUT do not decode high chars
  269.   //strcpybuff(fil,unescape_http_unharm(fil, 1));
  270.     // YES (not server side, but fs/client side)
  271.  
  272. #if HTS_USEMMS
  273.     /* .asx hack */
  274.     if (headers != NULL && headers->r.cdispo[0] != 0 
  275.         && strfield(headers->r.contenttype, "video/")
  276.         && strfield2(get_ext(OPT_GET_BUFF(opt),headers->r.cdispo), "asx") == 0) 
  277.     {
  278.         ext_chg = 1;
  279.         strcpybuff(ext, "asx");
  280.     }
  281.     else if (headers != NULL && headers->r.contenttype[0] != 0 
  282.         && strfield2(headers->r.contenttype, "video/x-ms-asf"))
  283.     {
  284.         char *exts = get_ext(OPT_GET_BUFF(opt),headers->url_fil);
  285.         if (strfield2(exts, "wmv") == 0)
  286.         {
  287.             ext_chg = 1;
  288.             strcpybuff(ext, "wmv");
  289.         }
  290.         else if (strfield2(exts, "asf") == 0)
  291.         {
  292.             ext_chg = 1;
  293.             strcpybuff(ext, "asf");
  294.         }
  295.         else if (strfield2(exts, "avi") == 0)
  296.         {
  297.             ext_chg = 1;
  298.             strcpybuff(ext, "avi");
  299.         }
  300.         else if (strfield2(exts, "asx") == 0)
  301.         {
  302.             ext_chg = 1;
  303.             strcpybuff(ext, "asx");
  304.         }
  305.     }
  306. #endif
  307.  
  308.   /* replace shtml to html.. */
  309.   if (opt->savename_delayed == 2)
  310.     is_html = -1;            /* ALWAYS delay type */
  311.   else
  312.     is_html = ishtml(opt,fil);
  313.   switch ( is_html ) {       /* .html,.shtml,.. */
  314.   case 1:
  315.     if ( 
  316.       (strfield2(get_ext(OPT_GET_BUFF(opt),fil),"html") == 0)
  317.       && (strfield2(get_ext(OPT_GET_BUFF(opt),fil),"htm") == 0)
  318.       )
  319.     {
  320.       strcpybuff(ext,"html");
  321.       ext_chg=1;
  322.     }
  323.     break;
  324.   case 0:
  325.     if (!strnotempty(ext)) {
  326.       if (is_userknowntype(opt,fil)) {      // mime known by user
  327.         char BIGSTK mime[1024];
  328.         mime[0]=ext[0]='\0';
  329.         get_userhttptype(opt,mime,fil);
  330.         if (strnotempty(mime)) {
  331.           give_mimext(ext,mime);
  332.           if (strnotempty(ext)) {
  333.             ext_chg=1;
  334.           }
  335.         }
  336.       }
  337.     }
  338.     break;
  339.   }
  340.  
  341.   // si option check_type activΘe
  342.   if (is_html < 0 && opt->check_type && !ext_chg) {
  343.     int ishtest=0;
  344.     if ( (!strfield(adr_complete,"file://")) 
  345.       && (!strfield(adr_complete,"ftp://")) 
  346. #if HTS_USEMMS
  347.       && (!strfield(adr_complete,"mms://")) 
  348. #endif
  349.       ) {
  350.       // tester type avec requΦte HEAD si on ne connait pas le type du fichier
  351.       if (!(   (opt->check_type==1) && (fil[strlen(fil)-1]=='/')   ))    // slash doit Ωtre html?
  352.       if ( opt->savename_delayed == 2 || (ishtest=ishtml(opt,fil)) < 0) { // on ne sait pas si c'est un html ou un fichier..
  353.         // lire dans le cache
  354.         htsblk r = cache_read_including_broken(opt,cache,adr,fil);              // test uniquement
  355.         if (r.statuscode != -1) {  // pas d'erreur de lecture cache
  356.           char s[16]; s[0]='\0';
  357.           if ( (opt->debug>1) && (opt->log!=NULL) ) {
  358.             HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"Testing link type (from cache) %s%s"LF,adr_complete,fil_complete);
  359.             test_flush;
  360.           }
  361.           if (strnotempty(r.cdispo)) {        /* filename given */
  362.             ext_chg=2;      /* change filename */
  363.             strcpybuff(ext,r.cdispo);
  364.           }
  365.           else if (!may_unknown2(opt,r.contenttype,fil) || ishtest == -2) {  // on peut patcher α priori?
  366.             give_mimext(s,r.contenttype);  // obtenir extension
  367.             if (strnotempty(s)>0) {        // on a reconnu l'extension
  368.               ext_chg=1;
  369.               strcpybuff(ext,s);
  370.             }
  371.           }
  372.           //
  373.         } else if ( opt->savename_delayed != 2 && is_userknowntype(opt,fil)) {   /* PATCH BY BRIAN SCHR╓DER. 
  374.                                                                             Lookup mimetype not only by extension, 
  375.                                                                             but also by filename */
  376.           /* Note: "foo.cgi => text/html" means that foo.cgi shall have the text/html MIME file type,
  377.           that is, ".html" */
  378.           char BIGSTK mime[1024];
  379.           mime[0]=ext[0]='\0';
  380.           get_userhttptype(opt, mime, fil);
  381.           if (strnotempty(mime)) {
  382.             give_mimext(ext, mime);
  383.             if (strnotempty(ext)) {
  384.               ext_chg=1;
  385.             }
  386.           }
  387.         }
  388.         // note: if savename_delayed is enabled, the naming will be temporary (and slightly invalid!)
  389.         else if (opt->savename_delayed != 0) {
  390.           if (mime_type != NULL)  {
  391.             ext[0] = '\0';
  392.             if (*mime_type) {
  393.               give_mimext(ext, mime_type);
  394.             }
  395.             if (strnotempty(ext)) {
  396.               char mime_from_file[128];
  397.               mime_from_file[0] = 0;
  398.               get_httptype(opt, mime_from_file, fil, 1);
  399.               if (!strnotempty(mime_from_file) || strcasecmp(mime_type, mime_from_file) != 0) {    /* different mime for this type */
  400.                 if (!may_unknown2(opt, mime_type, fil)) {
  401.                   ext_chg = 1;
  402.                 }
  403.               } else {
  404.                 ext_chg = 0;
  405.               }
  406.             }
  407.           } else {
  408.             /* Avoid collisions (no collisionning detection) */
  409.             sprintf(ext, "%x.%s", opt->state.delayedId++, DELAYED_EXT);
  410.             ext_chg = 1;
  411.                         ext_chg_delayed = 1;        /* due to naming system */
  412.           }
  413.         }
  414.         // test imposible dans le cache, faire une requΩte
  415.         else {
  416.           //
  417.           int hihp = opt->state._hts_in_html_parsing;
  418.           int has_been_moved=0;
  419.           char BIGSTK curr_adr[HTS_URLMAXSIZE*2],curr_fil[HTS_URLMAXSIZE*2];
  420.           
  421.           /* Ensure we don't use too many sockets by using a "testing" one
  422.              If we have only 1 simultaneous connection authorized, wait for pending download
  423.              Wait for an available slot 
  424.           */
  425.           URLSAVENAME_WAIT_FOR_AVAILABLE_SOCKET();
  426.  
  427.           /* Rock'in */
  428.           curr_adr[0]=curr_fil[0]='\0';
  429.          opt->state. _hts_in_html_parsing=2;  // test
  430.           if ( (opt->debug>1) && (opt->log!=NULL) ) {
  431.             HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"Testing link type %s%s"LF,adr_complete,fil_complete);
  432.             test_flush;
  433.           }
  434.           strcpybuff(curr_adr,adr_complete);
  435.           strcpybuff(curr_fil,fil_complete);
  436.           // ajouter dans le backing le fichier en mode test
  437.           // savename: rien car en mode test
  438.           if (back_add(sback,opt,cache,curr_adr,curr_fil,BACK_ADD_TEST,referer_adr,referer_fil,1)!=-1) {
  439.             int b;
  440.             b=back_index(opt,sback,curr_adr,curr_fil,BACK_ADD_TEST);         
  441.             if (b>=0) {
  442.               int stop_looping=0;
  443.               int petits_tours=0;
  444.               int get_test_request=0;       // en cas de bouclage sur soi mΩme avec HEAD, tester avec GET.. parfois c'est la cause des problΦmes
  445.               do {
  446.                 // temps α attendre, et remplir autant que l'on peut le cache (backing)
  447.                 if (back[b].status>0) {
  448.                   back_wait(sback,opt,cache,0);        
  449.                 }
  450.                 if (ptr>=0) {
  451.                                     back_fillmax(sback,opt,cache,liens,ptr,numero_passe,lien_tot);
  452.                                 }
  453.  
  454.                                 // on est obligΘ d'appeler le shell pour le refresh..
  455.                                 // Transfer rate
  456.                                 engine_stats();
  457.  
  458.                                 // Refresh various stats
  459.                                 HTS_STAT.stat_nsocket=back_nsoc(sback);
  460.                                 HTS_STAT.stat_errors=fspc(opt,NULL,"error");
  461.                                 HTS_STAT.stat_warnings=fspc(opt,NULL,"warning");
  462.                                 HTS_STAT.stat_infos=fspc(opt,NULL,"info");
  463.                                 HTS_STAT.nbk=backlinks_done(sback,liens,lien_tot,ptr);
  464.                                 HTS_STAT.nb=back_transfered(HTS_STAT.stat_bytes,sback);
  465.  
  466.                 if (!RUN_CALLBACK7(opt, loop, sback->lnk, sback->count,b,ptr,lien_tot,(int) (time_local()-HTS_STAT.stat_timestart),&HTS_STAT)) {
  467.                   return -1;
  468.                 } else if (opt->state._hts_cancel || !back_checkmirror(opt)) {    // cancel 2 ou 1 (cancel parsing)
  469.                   back_delete(opt,cache,sback,b);       // cancel test
  470.                   stop_looping = 1;
  471.                 }
  472.  
  473.                 // traitement des 304,303..
  474.                 if (back[b].status<=0) {
  475.                   if (HTTP_IS_REDIRECT(back[b].r.statuscode)) {    // agh moved.. un tit tour de plus
  476.                     if ((petits_tours<5) && (former_adr) && (former_fil)) { // on va pas tourner en rond non plus!
  477.                       if ((int) strnotempty(back[b].r.location)) {    // location existe!
  478.                         char BIGSTK mov_url[HTS_URLMAXSIZE*2],mov_adr[HTS_URLMAXSIZE*2],mov_fil[HTS_URLMAXSIZE*2];
  479.                         mov_url[0]=mov_adr[0]=mov_fil[0]='\0';
  480.                         //
  481.                         strcpybuff(mov_url,back[b].r.location);    // copier URL
  482.                         if (ident_url_relatif(mov_url,curr_adr,curr_fil,mov_adr,mov_fil)>=0) {                        
  483.                           // si non bouclage sur soi mΩme, ou si test avec GET non testΘ
  484.                           if ((strcmp(mov_adr,curr_adr)) || (strcmp(mov_fil,curr_fil)) || (get_test_request==0)) {
  485.                             // bouclage?
  486.                             if ((!strcmp(mov_adr,curr_adr)) && (!strcmp(mov_fil,curr_fil)))
  487.                               get_test_request=1;     // faire requΦte avec GET
  488.  
  489.                             // recopier former_adr/fil?
  490.                             if ((former_adr) && (former_fil)) {
  491.                               if (strnotempty(former_adr)==0) {    // Pas dΘja notΘ
  492.                                 strcpybuff(former_adr,curr_adr);
  493.                                 strcpybuff(former_fil,curr_fil);
  494.                               }
  495.                             }
  496.  
  497.                             // check explicit forbidden - don't follow 3xx in this case
  498.                             {
  499.                               int set_prio_to=0;
  500.                               if (hts_acceptlink(opt,ptr,lien_tot,liens,
  501.                                 mov_adr,mov_fil,
  502.                                 NULL, NULL,
  503.                                 &set_prio_to,
  504.                                 NULL) == 1) 
  505.                               {  /* forbidden */
  506.                                 has_been_moved = 1;
  507.                                 back_maydelete(opt,cache,sback,b);    // ok
  508.                                 strcpybuff(curr_adr,mov_adr);
  509.                                 strcpybuff(curr_fil,mov_fil);
  510.                                 mov_url[0]='\0';
  511.                                 stop_looping = 1;
  512.                               }
  513.                             }
  514.                             
  515.                             // ftp: stop!
  516.                             if (strfield(mov_url,"ftp://")
  517. #if HTS_USEMMS
  518.                                                             || strfield(mov_url,"mms://")
  519. #endif
  520.                                                             ) 
  521.                                                         {    // ftp, ok on arrΩte
  522.                               has_been_moved = 1;
  523.                               back_maydelete(opt,cache,sback,b);    // ok
  524.                               strcpybuff(curr_adr,mov_adr);
  525.                               strcpybuff(curr_fil,mov_fil);
  526.                               stop_looping = 1;
  527.                             } else if (*mov_url) {
  528.                               char* methode;
  529.                               if (!get_test_request)
  530.                                 methode=BACK_ADD_TEST;      // tester avec HEAD
  531.                               else {
  532.                                 methode=BACK_ADD_TEST2;     // tester avec GET
  533.                                 if ( opt->log!=NULL ) {
  534.                                   HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"Loop with HEAD request (during prefetch) at %s%s"LF,curr_adr,curr_fil);
  535.                                   test_flush;
  536.                                 }                    
  537.                               }
  538.                               // Ajouter
  539.                               URLSAVENAME_WAIT_FOR_AVAILABLE_SOCKET();
  540.                               if (back_add(sback,opt,cache,mov_adr,mov_fil,methode,referer_adr,referer_fil,1)!=-1) {    // OK
  541.                                 if ( (opt->debug>1) && (opt->log!=NULL) ) {
  542.                                   HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"(during prefetch) %s (%d) to link %s at %s%s"LF,back[b].r.msg,back[b].r.statuscode,back[b].r.location,curr_adr,curr_fil);
  543.                                   test_flush;
  544.                                 }
  545.                                 
  546.                                 // libΘrer emplacement backing actuel et attendre le prochain
  547.                                 back_maydelete(opt,cache,sback,b);
  548.                                 strcpybuff(curr_adr,mov_adr);
  549.                                 strcpybuff(curr_fil,mov_fil);
  550.                                 b=back_index(opt,sback,curr_adr,curr_fil,methode);         
  551.                                 if (!get_test_request)
  552.                                   has_been_moved = 1;       // sinon ne pas forcer has_been_moved car non dΘplacΘ
  553.                                 petits_tours++;
  554.                                 //
  555.                               } else {// sinon on fait rien et on s'en va.. (ftp etc)
  556.                                 if ( (opt->debug>1)  && (opt->log)) {
  557.                                   HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"Warning: Savename redirect backing error at %s%s"LF,mov_adr,mov_fil);
  558.                                   test_flush;
  559.                                 } 
  560.                               }
  561.                             }
  562.                           } else {
  563.                             if ( opt->log!=NULL ) {
  564.                               HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"Unable to test %s%s (loop to same filename)"LF,adr_complete,fil_complete);
  565.                               test_flush;
  566.                             }
  567.                           }
  568.                           
  569.                         }
  570.                       }
  571.                     } else{  // arrΩter les frais
  572.                       if ( opt->log!=NULL ) {
  573.                         HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"Unable to test %s%s (loop)"LF,adr_complete,fil_complete);
  574.                         test_flush;
  575.                       }
  576.                     }
  577.                   }  // ok, leaving
  578.                 }
  579.               } while(!stop_looping && back[b].status > 0 && back[b].status < 1000);
  580.               
  581.               // Si non dΘplacΘ, forcer type?
  582.               if (!has_been_moved) {
  583.                 if (back[b].r.statuscode!=-10) {    // erreur
  584.                   if (strnotempty(back[b].r.contenttype)==0)
  585.                     strcpybuff(back[b].r.contenttype,"text/html");    // message d'erreur en html
  586.                   // Finalement on, renvoie un erreur, pour ne toucher α rien dans le code
  587.                   // libΘrer emplacement backing
  588.                   /*if (opt->log!=NULL) {
  589.                     fspc(opt->log,0); fprintf(opt->log,"Error: (during prefetch) %s (%d) to link %s at %s%s"LF,back[b].r.msg,back[b].r.statuscode,back[b].r.location,curr_adr,curr_fil);
  590.                     test_flush;
  591.                   }                    
  592.                   back_delete(opt,cache,sback,b);
  593.                   return -1;        // ERREUR (404 par exemple)
  594.                   */
  595.                 } 
  596.                 
  597.                 {            // pas d'erreur, changer type?
  598.                   char s[16];
  599.                   s[0]='\0';
  600.                   if (strnotempty(back[b].r.cdispo)) {        /* filename given */
  601.                     ext_chg=2;      /* change filename */
  602.                     strcpybuff(ext,back[b].r.cdispo);
  603.                   }
  604.                   else if (!may_unknown2(opt, back[b].r.contenttype, back[b].url_fil) || ishtest == -2 ) {  // on peut patcher α priori? (pas interdit ou pas de type)
  605.                     give_mimext(s,back[b].r.contenttype);  // obtenir extension
  606.                     if (strnotempty(s)>0) {    // on a reconnu l'extension
  607.                       ext_chg=1;
  608.                       strcpybuff(ext,s);
  609.                     }
  610.                   }
  611.                 }
  612.               }
  613.               // FIN Si non dΘplacΘ, forcer type?
  614.  
  615.               // libΘrer emplacement backing
  616.               back_maydelete(opt,cache,sback,b);
  617.               
  618.               // --- --- ---
  619.               // oops, a ΘtΘ dΘplacΘ.. on recalcule en rΘcursif (osons!)
  620.               if (has_been_moved) {
  621.                 // copier adr, fil (optionnel, mais sinon marche pas pour le rip)
  622.                 strcpybuff(adr_complete,curr_adr);
  623.                 strcpybuff(fil_complete,curr_fil);
  624.                 // copier adr, fil
  625.                 
  626.                 return url_savename(curr_adr,curr_fil,save,NULL,NULL,referer_adr,referer_fil,opt,liens,lien_tot,sback,cache,hash,ptr,numero_passe,NULL);
  627.               }
  628.               // --- --- ---
  629.               
  630.             }
  631.             
  632.           } else {
  633.             printf("PANIC! : Savename Crash adding error, unexpected error found.. [%d]\n",__LINE__);
  634. #if BDEBUG==1
  635.             printf("error while savename crash adding\n");
  636. #endif
  637.             if (opt->log) {
  638.               HTS_LOG(opt,LOG_ERROR); fprintf(opt->log,"Unexpected savename backing error at %s%s"LF,adr,fil_complete);
  639.               test_flush;
  640.             } 
  641.             
  642.           }
  643.           // restaurer
  644.           opt->state._hts_in_html_parsing=hihp;
  645.         }  // cachΘ?
  646.       }
  647.     }
  648.   }
  649.  
  650.  
  651.  
  652.   // - - - DEBUT NOMMAGE - - -
  653.  
  654.   // Donner nom par dΘfaut?
  655.   if (fil[strlen(fil)-1]=='/')  {
  656.     if (!strfield(adr_complete,"ftp://")
  657. #if HTS_USEMMS
  658.             && !strfield(adr_complete,"mms://")
  659. #endif
  660.             )
  661.         {
  662.       strcatbuff(fil,DEFAULT_HTML);     // nommer page par dΘfaut!!
  663. #if HTS_USEMMS
  664.         } else if (strfield(adr_complete,"mms://")) {
  665.             strcatbuff(fil,DEFAULT_MMS);
  666. #endif
  667.         } else {
  668.       if (!opt->proxy.active)
  669.         strcatbuff(fil,DEFAULT_FTP);     // nommer page par dΘfaut (texte)
  670.       else
  671.         strcatbuff(fil,DEFAULT_HTML);     // nommer page par dΘfaut (α priori ici html depuis un proxy http)
  672.     }
  673.   }
  674.   // Changer extension?
  675.   // par exemple, php3 sera sauvΘ en html, cgi en html ou gif, xbm etc.. selon les cas
  676.   if (ext_chg) {  // changer ext
  677.     char* a=fil+strlen(fil)-1;
  678.     if ( (opt->debug>1) && (opt->log!=NULL) ) {
  679.       HTS_LOG(opt,LOG_DEBUG);
  680.       if (ext_chg==1)
  681.         fprintf(opt->log,"Changing link extension %s%s to .%s"LF,adr_complete,fil_complete,ext);
  682.       else
  683.         fprintf(opt->log,"Changing link name %s%s to %s"LF,adr_complete,fil_complete,ext);
  684.       test_flush;
  685.     }
  686.     if (ext_chg==1) {
  687.       while((a > fil) && (*a!='.') && (*a!='/')) a--;
  688.       if (*a=='.') *a='\0';  // couper
  689.       strcatbuff(fil,".");      // recopier point
  690.     } else {
  691.       while(( a > fil) && (*a!='/')) a--;
  692.       if (*a=='/') a++;
  693.       *a='\0';
  694.    }
  695.     strcatbuff(fil,ext);    // copier ext/nom
  696.   }
  697.  
  698.   // Rechercher premier / et dernier .
  699.   {  
  700.     char* a=fil+strlen(fil)-1;
  701.  
  702.     // passer structures
  703.     start_pos=fil;
  704.     while(( a > fil) && (*a != '/') && (*a != '\\')) {
  705.       if (*a == '.')    // point? noter position
  706.         if (!dot_pos)
  707.           dot_pos=a;
  708.         a--;
  709.     }
  710.     if ((*a=='/') || (*a=='\\')) a++;
  711.     nom_pos = a;
  712.   }
  713.  
  714.   
  715.   // un nom de fichier est gΘnΘrΘ
  716.   // s'il existe dΘja, alors on le mofifie lΘgΦrement
  717.  
  718.   // ajouter nom du site Θventuellement en premier
  719.   if (opt->savename_type == -1) {    // utiliser savename_userdef! (%h%p/%n%q.%t)
  720.     const char* a = StringBuff(opt->savename_userdef);
  721.     char* b = save;
  722.     /*char *nom_pos=NULL,*dot_pos=NULL;  // Position nom et point */
  723.     char tok;
  724.  
  725.     /*
  726.     {  // Rechercher premier /
  727.       char* a=fil+strlen(fil)-1;
  728.       // passer structures
  729.       while(((int) a>(int) fil) && (*a != '/') && (*a != '\\')) {
  730.         if (*a == '.')    // point? noter position
  731.         if (!dot_pos)
  732.           dot_pos=a;
  733.         a--;
  734.       }
  735.       if ((*a=='/') || (*a=='\\')) a++;
  736.       nom_pos = a;
  737.     }
  738.     */
  739.  
  740.     // Construire nom
  741.     while ((*a) && (((int) (b - save)) < HTS_URLMAXSIZE ) ) {    // parser, et pas trop long..
  742.       if (*a == '%') {
  743.         int short_ver=0;
  744.         a++;
  745.         if (*a == 's') {
  746.           short_ver=1;
  747.           a++;
  748.         }
  749.         *b='\0';
  750.         switch(tok=*a++) {
  751.           case '[':            // %[param:prefix_if_not_empty:suffix_if_not_empty:empty_replacement:notfound_replacement]
  752.             if (strchr(a,']')) {
  753.               int pos=0;
  754.               char name[5][256];
  755.               char* c=name[0];
  756.               for(pos = 0 ; pos < 5 ; pos++) {
  757.                 name[pos][0]='\0';
  758.               }
  759.               pos=0;
  760.               while(*a!=']') {
  761.                 if (pos < 5) {
  762.                   if (*a == ':') {  // next token
  763.                     c=name[++pos];
  764.                     a++;
  765.                   } else {
  766.                     *c++=*a++;
  767.                     *c='\0';
  768.                   }
  769.                 }
  770.               }
  771.               a++;
  772.               strcatbuff(name[0],"=");           /* param=.. */
  773.               c=strchr(fil_complete,'?');
  774.               /* parameters exists */
  775.               if (c) {
  776.                 char* cp;
  777.                 while((cp = strstr(c+1, name[0])) && *(cp-1) != '?' && *(cp-1) != '&') {     /* finds [?&]param= */
  778.                   c = cp;
  779.                 }
  780.                 if (cp) {
  781.                   c = cp + strlen(name[0]);    /* jumps "param=" */
  782.                   strcpybuff(b, name[1]);    /* prefix */
  783.                   b += strlen(b);
  784.                   if (*c != '\0' && *c != '&') {
  785.                     char* d = name[0];
  786.                     /* */
  787.                     while(*c != '\0' && *c != '&') {
  788.                       *d++ = *c++;
  789.                     }
  790.                     *d = '\0';
  791.                     d = unescape_http(catbuff,name[0]);
  792.                     if (d && *d) {
  793.                       strcpybuff(b, d);         /* value */
  794.                       b += strlen(b);
  795.                     } else {
  796.                       strcpybuff(b, name[3]);    /* empty replacement if any */
  797.                       b += strlen(b);
  798.                     }
  799.                   } else {
  800.                     strcpybuff(b, name[3]);    /* empty replacement if any */
  801.                     b += strlen(b);
  802.                   }
  803.                   strcpybuff(b, name[2]);    /* suffix */
  804.                   b += strlen(b);
  805.                 } else {
  806.                   strcpybuff(b, name[4]);    /* not found replacement if any */
  807.                   b += strlen(b);
  808.                 }
  809.                             } else {
  810.                                 strcpybuff(b, name[4]);    /* not found replacement if any */
  811.                                 b += strlen(b);
  812.                             }
  813.             }
  814.           break;
  815.           case '%': *b++='%'; break;
  816.           case 'n':    // nom sans ext
  817.             *b='\0';
  818.             if (dot_pos) {
  819.               if (!short_ver)    // Noms longs
  820.                 strncatbuff(b,nom_pos,(int) (dot_pos - nom_pos));
  821.               else
  822.                 strncatbuff(b,nom_pos,min((int) (dot_pos - nom_pos),8));
  823.             } else {
  824.               if (!short_ver)    // Noms longs
  825.                 strcpybuff(b,nom_pos);
  826.               else
  827.                 strncatbuff(b,nom_pos,8);
  828.             }
  829.             b+=strlen(b);   // pointer α la fin
  830.             break;
  831.           case 'N':    // nom avec ext
  832.             // RECOPIE NOM + EXT
  833.             *b='\0';
  834.             if (dot_pos) {
  835.               if (!short_ver)    // Noms longs
  836.                 strncatbuff(b,nom_pos,(int) (dot_pos - nom_pos));
  837.               else
  838.                 strncatbuff(b,nom_pos,min((int) (dot_pos - nom_pos),8));
  839.             } else {
  840.               if (!short_ver)    // Noms longs
  841.                 strcpybuff(b,nom_pos);
  842.               else
  843.                 strncatbuff(b,nom_pos,8);
  844.             }
  845.             b+=strlen(b);   // pointer α la fin
  846.             // RECOPIE NOM + EXT
  847.             *b='\0';
  848.             if (dot_pos) {
  849.               if (!short_ver)    // Noms longs
  850.                 strcpybuff(b,dot_pos+1);
  851.               else
  852.                 strncatbuff(b,dot_pos+1,3);
  853.             } else {
  854.               if (!short_ver)    // Noms longs
  855.                 strcpybuff(b,DEFAULT_EXT + 1);    // pas de..
  856.               else
  857.                 strcpybuff(b,DEFAULT_EXT_SHORT + 1);    // pas de..
  858.             }
  859.             b+=strlen(b);   // pointer α la fin
  860.             //
  861.             break;
  862.           case 't':    // ext
  863.             *b='\0';
  864.             if (dot_pos) {
  865.               if (!short_ver)    // Noms longs
  866.                 strcpybuff(b,dot_pos+1);
  867.               else
  868.                 strncatbuff(b,dot_pos+1,3);
  869.             } else {
  870.               if (!short_ver)    // Noms longs
  871.                 strcpybuff(b,DEFAULT_EXT + 1);    // pas de..
  872.               else
  873.                 strcpybuff(b,DEFAULT_EXT_SHORT + 1);    // pas de..
  874.             }
  875.             b+=strlen(b);   // pointer α la fin
  876.             break;
  877.           case 'p':    // path sans dernier /
  878.             *b='\0';
  879.             if (nom_pos != fil + 1) { // pas: /index.html (chemin nul)
  880.               if (!short_ver) {   // Noms longs
  881.                 strncatbuff(b,fil,(int) (nom_pos - fil) - 1);
  882.               } else {
  883.                 char BIGSTK pth[HTS_URLMAXSIZE*2],n83[HTS_URLMAXSIZE*2];
  884.                 pth[0]=n83[0]='\0';
  885.                 //
  886.                 strncatbuff(pth,fil,(int) (nom_pos - fil) - 1);
  887.                 long_to_83(opt->savename_83,n83,pth);
  888.                 strcpybuff(b,n83);
  889.               }
  890.             }
  891.             b+=strlen(b);   // pointer α la fin
  892.             break;
  893.           case 'h':    // host
  894.             *b='\0';
  895.             if (strcmp(adr_complete,"file://")==0) {
  896.               if (!short_ver)    // Noms longs
  897.                 strcpybuff(b,"localhost");
  898.               else
  899.                 strcpybuff(b,"local");
  900.             } else {
  901.               if (!short_ver)    // Noms longs
  902.                 strcpybuff(b,print_adr);
  903.               else
  904.                 strncatbuff(b,print_adr,8);
  905.             }
  906.             b+=strlen(b);   // pointer α la fin
  907.             break;
  908.           case 'M':         /* host/address?query MD5 (128-bits) */
  909.             *b='\0';
  910.             {
  911.               char digest[32+2];
  912.               char BIGSTK buff[HTS_URLMAXSIZE*2];
  913.               digest[0]=buff[0]='\0';
  914.               strcpybuff(buff,adr);
  915.               strcatbuff(buff,fil_complete);
  916.               domd5mem(buff,strlen(buff),digest,1);
  917.               strcpybuff(b,digest);
  918.             }
  919.             b+=strlen(b);   // pointer α la fin
  920.             break;
  921.           case 'Q': case 'q':         /* query MD5 (128-bits/16-bits) 
  922.                                          GENERATED ONLY IF query string exists! */
  923.                         {
  924.                             char md5[32 + 2];
  925.                             *b='\0';
  926.                             strncatbuff(b,url_md5(md5, fil_complete),(tok == 'Q')?32:4);
  927.                             b+=strlen(b);   // pointer α la fin
  928.                         }
  929.             break;
  930.           case 'r': case 'R':        // protocol
  931.             *b='\0';
  932.             strcatbuff(b, protocol_str[protocol]);
  933.             b+=strlen(b);   // pointer α la fin
  934.           break;
  935.  
  936.       /* Patch by Juan Fco Rodriguez to get the full query string */
  937.       case 'k':
  938.         {
  939.           char *d = strchr(fil_complete,'?');
  940.           if( d != NULL )
  941.           {
  942.             strcatbuff(b, d);
  943.             b+=strlen(b);
  944.           }
  945.         }
  946.         break;
  947.  
  948.         }
  949.       } else
  950.         *b++=*a++;
  951.     }
  952.     *b++='\0';
  953.     //
  954.     // Types prΘdΘfinis
  955.     //
  956.  
  957.   } 
  958.   //
  959.   // Structure originale
  960.   else if (opt->savename_type%100==0) { 
  961.     /* recopier www.. */
  962.     if (opt->savename_type!=100) {  
  963.       if (((opt->savename_type/1000)%2)==0) {    // >1000 signifie "pas de www/"
  964.         if (strcmp(adr_complete,"file://")==0) {
  965.           //## if (*adr==lOCAL_CHAR) {
  966.           if (opt->savename_83 != 1)  // noms longs
  967.             strcatbuff(save,"localhost");
  968.           else
  969.             strcatbuff(save,"local");
  970.         } else {
  971.           // adresse url
  972.           if (!opt->savename_83) {  // noms longs (et pas de .)
  973.             strcatbuff(save,print_adr);
  974.           } else {  // noms 8-3
  975.             if (strlen(print_adr)>4) {
  976.               if (strfield(print_adr,"www."))
  977.                 strncatbuff(save,print_adr+4,max_char);
  978.               else
  979.                 strncatbuff(save,print_adr,8);
  980.             } else strncatbuff(save,print_adr,max_char);
  981.           }
  982.         }
  983.         if (*fil!='/') strcatbuff(save,"/");
  984.       }
  985.     }
  986.   
  987.     hts_lowcase(save);
  988.         
  989.     /*
  990.     // ne sert α rien car a dΘja ΘtΘ filtrΘ normalement
  991.     if ((*fil=='.') && (*(fil+1)=='/'))          // ./index.html ** //
  992.       url_savename_addstr(save,fil+2);
  993.     else                                               // index.html ou /index.html
  994.       url_savename_addstr(save,fil);
  995.     if (save[strlen(save)-1]=='/') 
  996.       strcatbuff(save,DEFAULT_HTML);     // nommer page par dΘfaut!!
  997. */
  998.  
  999.     /* add name */
  1000.     ADD_STANDARD_PATH;
  1001.     ADD_STANDARD_NAME(0);
  1002.  
  1003.   }
  1004.   //
  1005.   // Structure html/image
  1006.   else {    
  1007.     // dossier "web" ou "www.xxx" ?
  1008.     if (((opt->savename_type/1000)%2)==0) {    // >1000 signifie "pas de www/"
  1009.       if ((opt->savename_type/100)%2) {
  1010.         if (strcmp(adr_complete,"file://")==0) {
  1011.         //## if (*adr==lOCAL_CHAR) {
  1012.           if (opt->savename_83 != 1)  // noms longs
  1013.             strcatbuff(save,"localhost/");
  1014.           else
  1015.             strcatbuff(save,"local/");
  1016.         } else {
  1017.           // adresse url
  1018.           if (!opt->savename_83) {  // noms longs
  1019.             strcatbuff(save,print_adr); strcatbuff(save,"/");
  1020.           } else {  // noms 8-3
  1021.             if (strlen(print_adr)>4) {
  1022.               if (strfield(print_adr,"www."))
  1023.                 strncatbuff(save,print_adr+4,max_char);
  1024.               else
  1025.                 strncatbuff(save,print_adr,max_char);
  1026.               strcatbuff(save,"/");
  1027.             } else { 
  1028.               strncatbuff(save,print_adr,max_char); strcatbuff(save,"/");
  1029.             }
  1030.           }
  1031.         }
  1032.       } else {
  1033.         strcatbuff(save,"web/");    // rΘpertoire gΘnΘral
  1034.       }
  1035.     } 
  1036.  
  1037.     // si un html α coup s√r
  1038.     if ( (ext_chg!=0) ? (ishtml_ext(ext) == 1) : (ishtml(opt,fil)==1) ) {
  1039.       if (opt->savename_type%100==2) {  // html/
  1040.         strcatbuff(save, "html/");
  1041.       }
  1042.     } else {
  1043.       if ((opt->savename_type%100==1) || (opt->savename_type%100==2)) {  // html & images
  1044.         strcatbuff(save, "images/");
  1045.       }
  1046.     }
  1047.     
  1048.     switch (opt->savename_type%100) {
  1049.     case 4: case 5: {           // sΘparer par types
  1050.       char* a=fil+strlen(fil)-1;
  1051.       // passer structures
  1052.       while(( a > fil) && (*a != '/') && (*a != '\\')) a--;      
  1053.       if ((*a=='/') || (*a=='\\')) a++;
  1054.  
  1055.       // html?
  1056.       if ( (ext_chg!=0) ? (ishtml_ext(ext)==1) : (ishtml(opt,fil)==1) ) {
  1057.         if (opt->savename_type%100==5)
  1058.           strcatbuff(save,"html/");
  1059.       } else {
  1060.         char* a=fil+strlen(fil)-1;
  1061.         while(( a> fil) && (*a != '/') && (*a != '.')) a--;      
  1062.         if (*a!='.')
  1063.           strcatbuff(save,"other");
  1064.         else
  1065.           strcatbuff(save,a+1);
  1066.         strcatbuff(save,"/");
  1067.       }
  1068.       /*strcatbuff(save,a);*/
  1069.       /* add name */
  1070.       ADD_STANDARD_NAME(0);
  1071.             }
  1072.       break;
  1073.     case 99: {                  // 'codΘ' .. c'est un gadget
  1074.       int i;
  1075.       int j;
  1076.       char* a;
  1077.       char C[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-";
  1078.       int L;
  1079.       // pseudo-CRC sur fil et adr pour initialiser gΘnΘrateur alΘatoire..
  1080.       unsigned int s=0;
  1081.       L = (int) strlen(C);
  1082.       for(i=0;i<(int) strlen(fil_complete);i++) {
  1083.         s+=(unsigned int) fil_complete[i];
  1084.       }
  1085.       for(i=0;i<(int) strlen(adr_complete);i++) {
  1086.         s+=(unsigned int) adr_complete[i];
  1087.       }
  1088.       srand(s);
  1089.       
  1090.       j = (int) strlen(save);
  1091.       for(i=0;i<8;i++) {
  1092.         char c=C[(rand()%L)];
  1093.         save[i+j]=c;
  1094.       }
  1095.       save[i+j]='\0';
  1096.       // ajouter extension
  1097.       a = fil + strlen(fil) - 1;
  1098.       while(( a > fil) && (*a != '/') && (*a != '.')) a--;
  1099.       if (*a=='.') {
  1100.         strcatbuff(save,a);    // ajouter
  1101.       }
  1102.              } 
  1103.       break;
  1104.     default: {   // noms sans les noms des rΘpertoires
  1105.       // ne garder que le nom, pas la structure
  1106.       /*
  1107.       char* a=fil+strlen(fil)-1;
  1108.       while(((int) a>(int) fil) && (*a != '/') && (*a != '\\')) a--;      
  1109.       if ((*a=='/') || (*a=='\\')) a++;
  1110.       strcatbuff(save,a);
  1111.       */
  1112.  
  1113.       /* add name */
  1114.       ADD_STANDARD_NAME(0);
  1115.             }
  1116.       break;
  1117.     }
  1118.  
  1119.     hts_lowcase(save);
  1120.  
  1121.     if (save[strlen(save)-1]=='/') 
  1122.       strcatbuff(save,DEFAULT_HTML);     // nommer page par dΘfaut!!
  1123.   }
  1124.  
  1125.  
  1126.   // vΘrifier qu'on ne doit pas forcer l'extension
  1127.   // par exemple, asp sera sauvΘ en html, cgi en html ou gif, xbm etc.. selon les cas
  1128.   /*if (ext_chg) {
  1129.     char* a=save+strlen(save)-1;
  1130.     while(((int) a>(int) save) && (*a!='.') && (*a!='/')) a--;
  1131.     if (*a=='.') *a='\0';  // couper
  1132.     // recopier extension
  1133.     strcatbuff(save,".");
  1134.     strcatbuff(save,ext);    // copier ext
  1135.   }*/
  1136.   // de mΩme en cas de manque d'extension on en place une de maniΦre forcΘe..
  1137.   // cela Θvite les /chez/toto et les /chez/toto/index.html incompatibles
  1138.   if (opt->savename_type != -1) {
  1139.     char* a=save+strlen(save)-1;
  1140.     while(( a > save) && (*a!='.') && (*a!='/')) a--;
  1141.     if (*a!='.') {   // agh pas de point
  1142.       //strcatbuff(save,".none");                 // a Θviter
  1143.       strcatbuff(save,".html");                   // prΘfΘrable!
  1144.       if ( (opt->debug>1) && (opt->log!=NULL) ) {
  1145.         HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"Default HTML type set for %s%s"LF,adr_complete,fil_complete);
  1146.         test_flush;
  1147.       }
  1148.     }
  1149.   }
  1150.  
  1151.   // effacer pass au besoin pour les autentifications
  1152.   // (plus la peine : masquΘ au dΘbut)
  1153. /*
  1154.   {
  1155.     char* a=jump_identification(save);
  1156.     if (a!=save) {
  1157.       char BIGSTK tempo[HTS_URLMAXSIZE*2];
  1158.       char *b;
  1159.       tempo[0]='\0';
  1160.       strcpybuff(tempo,"[");
  1161.       b=strchr(save,':');
  1162.       if (!b) b=strchr(save,'@');
  1163.       if (b)
  1164.         strncatbuff(tempo,save,(int) b-(int) a);
  1165.       strcatbuff(tempo,"]");
  1166.       strcatbuff(tempo,a);
  1167.       strcpybuff(save,a);
  1168.     }
  1169.   }
  1170. */
  1171.  
  1172.   // Θviter les / au dΘbut (cause: N100)
  1173.   if (save[0]=='/') {
  1174.     char BIGSTK tempo[HTS_URLMAXSIZE*2];
  1175.     strcpybuff(tempo,save+1);
  1176.     strcpybuff(save,tempo);
  1177.   }
  1178.  
  1179.   // changer les ~,:,",*,? en _ pour sauver sur disque
  1180.   hts_replace(save,'~','_');  // interdit sous unix (~foo)
  1181.   //
  1182.   hts_replace(save,'\\','_');
  1183.   hts_replace(save,':','_');  // interdit sous windows
  1184.   hts_replace(save,'*','_');  // interdit sous windows
  1185.   hts_replace(save,'?','_');  // doit pas arriver!!
  1186.   hts_replace(save,'\"','_');  // interdit sous windows
  1187.   hts_replace(save,'<','_');  // interdit sous windows
  1188.   hts_replace(save,'>','_');  // interdit sous windows
  1189.   hts_replace(save,'|','_');  // interdit sous windows
  1190.   //
  1191.   hts_replace(save,'@','_');
  1192.   if (opt->savename_83 == 2) { // CDROM
  1193.     // maybe other ones?
  1194.     hts_replace(save,'-','_');
  1195.     hts_replace(save,'=','_');
  1196.     hts_replace(save,'+','_');
  1197.   }
  1198.   //
  1199.   { // Θliminer les // (comme ftp://)
  1200.     char* a;
  1201.     while( (a=strstr(save,"//")) ) *a='_';
  1202.     // Eliminer chars spΘciaux
  1203.     a=save -1 ;
  1204.     while(*(++a))
  1205.       if ( ((unsigned char)(*a) <= 31)
  1206.           || ((unsigned char)(*a) == 127) )
  1207.         *a='_';
  1208.   }
  1209.  
  1210.    
  1211. #if HTS_OVERRIDE_DOS_FOLDERS
  1212.   /* Replace /foo/nul/bar by /foo/nul_/bar */
  1213.   {
  1214.     int i=0;
  1215.     while(hts_tbdev[i][0]) {
  1216.       char* a=save;
  1217.       while((a=strstrcase(a,(char*)hts_tbdev[i]))) {
  1218.         switch ( (int) a[strlen(hts_tbdev[i])] ) {
  1219.         case '\0':
  1220.         case '/':
  1221.         case '.': 
  1222.         {
  1223.           char BIGSTK tempo[HTS_URLMAXSIZE*2]; tempo[0]='\0';
  1224.           strncatbuff(tempo,save,(int) (a - save) + strlen(hts_tbdev[i]));
  1225.           strcatbuff(tempo,"_");
  1226.           strcatbuff(tempo,a+strlen(hts_tbdev[i]));
  1227.           strcpybuff(save,tempo);
  1228.                    }
  1229.           break;
  1230.         }
  1231.         a+=strlen(hts_tbdev[i]);
  1232.       }
  1233.       i++;
  1234.     }
  1235.   }
  1236.   /* Strip ending . or ' ' forbidden on windoz */
  1237.   {
  1238.     int len;
  1239.     char* a=save;
  1240.     while((a=strstr(a,"./"))) {
  1241.       *a = '_';
  1242.     }
  1243.     a=save;
  1244.     while((a=strstr(a," /"))) {
  1245.       *a = '_';
  1246.     }
  1247.     len = (int) strlen(save);
  1248.     if (len > 0 && ( save[len - 1] == '.' || save[len - 1] == ' ') ) {
  1249.       save[len - 1] = '_';
  1250.     }
  1251.   }
  1252. #endif
  1253.  
  1254.   // conversion 8-3 .. y compris pour les rΘpertoires
  1255.   if (opt->savename_83) {
  1256.     char BIGSTK n83[HTS_URLMAXSIZE*2];
  1257.     long_to_83(opt->savename_83,n83,save);
  1258.     strcpybuff(save,n83);
  1259.   }
  1260.  
  1261.   // enforce stricter ISO9660 compliance (bug reported by Steffo Carlsson)
  1262.   // Level 1 File names are restricted to 8 characters with a 3 character extension, 
  1263.   // upper case letters, numbers and underscore; maximum depth of directories is 8.
  1264.   // This will be our "DOS mode"
  1265.   // L2: 31 characters
  1266.   // A-Z,0-9,_
  1267.   if (opt->savename_83 > 0) {
  1268.     char *a, *last;
  1269.     for(last = save + strlen(save) - 1 ; last != save && *last != '/' && *last != '\\' && *last != '.' ; last--);
  1270.     if (*last != '.') {
  1271.       last = NULL;
  1272.     }
  1273.     for(a = save ; *a != '\0' ; a++) {
  1274.       if (*a >= 'a' && *a <= 'z') {
  1275.         *a -= 'a' - 'A';
  1276.       }
  1277.       else if (*a == '.') {
  1278.         if (a != last) {
  1279.           *a = '_';
  1280.         }
  1281.       }
  1282.       else if ( ! ( (*a >= 'A' && *a <= 'Z') || (*a >= '0' && *a <= '9') || *a == '_' || *a == '/' || *a == '\\') ) {
  1283.         *a = '_';
  1284.       }
  1285.     }
  1286.   }
  1287.  
  1288.   /* ensure that there is no ../ (potential vulnerability) */
  1289.   fil_simplifie(save);
  1290.  
  1291.     /* callback */
  1292.   RUN_CALLBACK5(opt, savename, adr_complete,fil_complete,referer_adr,referer_fil,save);
  1293.  
  1294.   if ( (opt->debug>0) && (opt->log!=NULL) ) {
  1295.         HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"engine: save-name: local name: %s%s -> %s"LF,adr,fil,save);
  1296.         test_flush;
  1297.     }
  1298.  
  1299.     /* Ensure that the MANDATORY "temporary" extension is set */
  1300.     if (ext_chg_delayed) {
  1301.         char *ptr;
  1302.         char *lastDot = NULL;
  1303.         for(ptr = save ; *ptr != 0 ; ptr++) {
  1304.             if (*ptr == '.') {
  1305.                 lastDot = ptr;
  1306.             } else if (*ptr == '/' || *ptr == '\\') {
  1307.                 lastDot = NULL;
  1308.             }
  1309.         }
  1310.         if (lastDot == NULL) {
  1311.             strcatbuff(save, "." DELAYED_EXT);
  1312.         } else if (!IS_DELAYED_EXT(save)) {
  1313.             strcatbuff(lastDot, "." DELAYED_EXT);
  1314.         }
  1315.     }
  1316.  
  1317.   // chemin primaire Θventuel A METTRE AVANT
  1318.   if (strnotempty(StringBuff(opt->path_html))) {
  1319.     char BIGSTK tempo[HTS_URLMAXSIZE*2];
  1320.     strcpybuff(tempo,StringBuff(opt->path_html));
  1321.     strcatbuff(tempo,save);
  1322.     strcpybuff(save,tempo);
  1323.   }
  1324.  
  1325.  
  1326.   // vΘrifier que le nom n'est pas dΘja pris...
  1327.   if (liens!=NULL) { 
  1328.     int nom_ok;
  1329.     do {
  1330.       int i;
  1331.       //
  1332.       nom_ok=1;  // α priori bon
  1333.       // on part de la fin pour optimiser, plus les opti de taille pour aller encore plus vite..
  1334. #if DEBUG_SAVENAME
  1335. printf("\nStart search\n");
  1336. #endif
  1337.  
  1338.       i=hash_read(hash,save,"",0,0);      // lecture type 0 (sav)
  1339.       if (i>=0)
  1340.           {
  1341.             int sameAdr = ( strfield2(liens[i]->adr, normadr) != 0 );
  1342.             int sameFil;
  1343.                         // NO - URL hack is only for stripping // and www.
  1344.             //if (opt->urlhack != 0)
  1345.             //  sameFil = ( strfield2(liens[i]->fil, normfil) != 0);
  1346.             //else
  1347.             sameFil = ( strcmp(liens[i]->fil, normfil) == 0);
  1348.             if (sameAdr && sameFil)
  1349.             {    // ok c'est le mΩme lien, adresse dΘja dΘfinie
  1350.               /* Take the existing name not to screw up with cAsE sEnSiTiViTy of Linux/Unix */
  1351.               if (strcmp(liens[i]->sav, save) != 0) {
  1352.                 strcpybuff(save, liens[i]->sav);
  1353.               }
  1354.               i=0;
  1355. #if DEBUG_SAVENAME
  1356. printf("\nOK ALREADY DEFINED\n",13,i);
  1357. #endif
  1358.             } else {  // utilisΘ par un AUTRE, changer de nom
  1359.               char BIGSTK tempo[HTS_URLMAXSIZE*2];
  1360.               char* a=save+strlen(save)-1;
  1361.               char* b;
  1362.               int n=2;       
  1363.               char collisionSeparator = ( (opt->savename_83 != 2) ? '-' : '_');
  1364.               tempo[0]='\0';
  1365.  
  1366. #if DEBUG_SAVENAME
  1367. printf("\nWRONG CASE UNMATCH : \n%s\n%s, REDEFINE\n",liens[i]->fil,fil_complete);
  1368. #endif
  1369.               nom_ok=0;
  1370.               i=0;
  1371.               
  1372.               while(( a > save) && (*a!='.') && (*a!='\\') && (*a!='/')) a--;
  1373.               if (*a=='.')
  1374.                 strncatbuff(tempo,save,(int) (a - save));
  1375.               else
  1376.                 strcatbuff(tempo,save);
  1377.               
  1378.               // tester la prΘsence d'un -xx (ex: index-2.html -> index-3.html)
  1379.               b=tempo+strlen(tempo)-1;
  1380.               while (isdigit((unsigned char)*b)) b--;
  1381.               if (*b == collisionSeparator) {
  1382.                 sscanf(b+1,"%d",&n);
  1383.                 *b='\0';    // couper
  1384.                 n++;  // plus un
  1385.               }
  1386.               
  1387.               // en plus il faut gΘrer le 8-3 .. pas facile le client
  1388.               if (opt->savename_83) {
  1389.                 int max;
  1390.                 char* a=tempo+strlen(tempo)-1;
  1391.                 while(( a > tempo) && (*a!='/')) a--;
  1392.                 if (*a=='/') a++;
  1393.                 max=max_char-1-nombre_digit(n);
  1394.                 if ((int) strlen(a)>max)
  1395.                   *(a+max)='\0';  // couper sinon il n'y aura pas la place!
  1396.               }
  1397.               
  1398.               // ajouter -xx (ex: index.html -> index-2.html)
  1399.               sprintf(tempo+strlen(tempo),"%c%d", collisionSeparator, n);
  1400.               
  1401.               // ajouter extension
  1402.               if (*a=='.')
  1403.                 strcatbuff(tempo,a);
  1404.               
  1405.               strcpybuff(save,tempo);
  1406.               
  1407.               //printf("switched: %s\n",save);
  1408.               
  1409.             }  // if
  1410.           }
  1411. #if DEBUG_SAVENAME
  1412. printf("\nEnd search, %s\n",fil_complete);
  1413. #endif
  1414.     } while(!nom_ok);
  1415.     
  1416.   }
  1417.   
  1418.   //printf("'%s' %s %s\n",save,adr,fil);
  1419.       
  1420.   return 0;
  1421. }
  1422.  
  1423. /* nom avec md5 urilisΘ partout */
  1424. void standard_name(char* b,char* dot_pos,char* nom_pos,char* fil_complete,int short_ver) {
  1425.     char md5[32 + 2];
  1426.  
  1427.   b[0]='\0';
  1428.   /* Nom */
  1429.   if (dot_pos) {
  1430.     if (!short_ver)    // Noms longs
  1431.       strncatbuff(b,nom_pos,(int) (dot_pos - nom_pos));
  1432.     else
  1433.       strncatbuff(b,nom_pos,min((int) (dot_pos - nom_pos),8));
  1434.   } else {
  1435.     if (!short_ver)    // Noms longs
  1436.       strcatbuff(b,nom_pos);
  1437.     else
  1438.       strncatbuff(b,nom_pos,8);
  1439.   }
  1440.   /* MD5 - 16 bits */
  1441.   strncatbuff(b,url_md5(md5,fil_complete),4);
  1442.   /* Ext */
  1443.   if (dot_pos) {
  1444.     strcatbuff(b,".");
  1445.     if (!short_ver)    // Noms longs
  1446.       strcatbuff(b,dot_pos+1);
  1447.     else
  1448.       strncatbuff(b,dot_pos+1,3);
  1449.   } else {
  1450.     if (!short_ver)    // Noms longs
  1451.       strcatbuff(b,DEFAULT_EXT + 1);    // pas de..
  1452.     else
  1453.       strcatbuff(b,DEFAULT_EXT_SHORT + 1);    // pas de..
  1454.   }
  1455. }
  1456.  
  1457.  
  1458. /* Petit md5 */
  1459. char* url_md5(char* digest, char* fil_complete) {
  1460.   char* a;
  1461.   digest[0]='\0';
  1462.   a=strchr(fil_complete,'?');
  1463.   if (a) {
  1464.     if (strlen(a)) {
  1465.       char BIGSTK buff[HTS_URLMAXSIZE*2];
  1466.       a++;
  1467.       digest[0]=buff[0]='\0';
  1468.       strcatbuff(buff,a);         /* query string MD5 */
  1469.       domd5mem(buff,strlen(buff),digest,1);
  1470.     }
  1471.   }
  1472.   return digest;
  1473. }
  1474.  
  1475. // interne α url_savename: ajoute une chaεne α une autre avec \ -> /
  1476. void url_savename_addstr(char* d,char* s) {
  1477.   int i = (int) strlen(d);
  1478.   while(*s) {
  1479.     if (*s=='\\')  // remplacer \ par des /
  1480.       d[i++]='/';
  1481.     else
  1482.       d[i++]=*s;
  1483.     s++;
  1484.   }
  1485.   d[i]='\0';
  1486. }
  1487.  
  1488. /* "filename" should be at least 64 bytes. */
  1489. void url_savename_refname(const char *adr, const char *fil, char *filename) {
  1490.   unsigned char bindigest[16];
  1491.   MD5_CTX ctx;
  1492.   MD5Init(&ctx, 0);
  1493.   MD5Update(&ctx, adr, (unsigned int) strlen(adr));
  1494.   MD5Update(&ctx, ",", 1);
  1495.   MD5Update(&ctx, fil, (unsigned int) strlen(fil));
  1496.   MD5Final(bindigest, &ctx);
  1497.   sprintf(filename, CACHE_REFNAME "/"
  1498.     "%02x%02x%02x%02x%02x%02x%02x%02x"
  1499.     "%02x%02x%02x%02x%02x%02x%02x%02x"
  1500.     ".ref",
  1501.     bindigest[0],  bindigest[1],  bindigest[2],  bindigest[3],
  1502.     bindigest[4],  bindigest[5],  bindigest[6],  bindigest[7],
  1503.     bindigest[8],  bindigest[9],  bindigest[10], bindigest[11],
  1504.     bindigest[12], bindigest[13], bindigest[14], bindigest[15]);
  1505. }
  1506.  
  1507. char *url_savename_refname_fullpath(httrackp* opt, const char *adr, const char *fil) {
  1508.   char digest_filename[64];
  1509.   url_savename_refname(adr, fil, digest_filename);
  1510.   return fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log), digest_filename);
  1511. }
  1512.  
  1513. /* remove refname if any */
  1514. void url_savename_refname_remove(httrackp* opt, const char *adr, const char *fil) {
  1515.   char *filename = url_savename_refname_fullpath(opt, adr, fil);
  1516.   (void) unlink(filename);
  1517. }
  1518.  
  1519. #undef test_flush
  1520.